package com.snda.dsync;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.VFS;

public class VFSSyncer extends VFSPusher {
	private Log log = LogFactory.getLog(VFSSyncer.class);
	public static String DEFAULTTMP = ".dsynctmp";

	private URL from;
	private URL to;
	boolean delete = false;
	private Set<String> ignore = new HashSet<String>();
	public String path;

	public VFSSyncer(URL from, URL to) {
		super();
		this.from = from;
		this.to = to;
		ignore.add(DEFAULTTMP);
	}

	public VFSSyncer(URL from, URL to, boolean delete) {
		super();
		this.from = from;
		this.to = to;
		this.delete = delete;
		ignore.add(DEFAULTTMP);

	}

	public VFSSyncer(URL from, URL to, boolean delete, String[] ignore) {
		super();
		this.from = from;
		this.to = to;
		this.delete = delete;
		this.ignore.add(DEFAULTTMP);
		addIgnore(ignore);
	}

	void addIgnore(String[] ignores) {
		for (String string : ignores) {
			this.ignore.add(string);
		}
	}

	public void run() throws FileSystemException {
		log.info("sync dir " + from + " to " + to);
		FileObject fromdir = resolveFile(from);
		FileObject todir = resolveFile(to);
		FileObject tmpdir = tmpdir(todir);
		for (FileObject from : tree(fromdir)) {
			try {
				FileObject to = aimDataFile(from, fromdir, todir);
				boolean success = push(from, to, tmpdir, true);
				if (success && delete) {
					log.info("delete " + from.getURL());
					from.delete();
				}
			} catch (FileSystemException e) {
				e.printStackTrace();
			}
		}
	}

	private FileObject tmpdir(FileObject todir) throws FileSystemException {
		FileObject tmpdir = VFS.getManager().resolveFile(todir, DEFAULTTMP);
		if (!tmpdir.exists())
			tmpdir.createFolder();
		return tmpdir;
	}

	protected FileObject aimDataFile(FileObject from, FileObject fromdir,
			FileObject todir) throws FileSystemException {
		LinkedList<String> names = new LinkedList<String>();
		FileObject parent = from.getParent();
		while (!parent.getName().getPath().equals(fromdir.getName().getPath())) {
			names.addFirst(parent.getName().getBaseName());
			parent = parent.getParent();
		}
		parent = todir;
		for (String name : names) {
			parent = VFS.getManager().resolveFile(parent, name);
		}
		return VFS.getManager().resolveFile(parent,
				from.getName().getBaseName());
	}

	public List<FileObject> tree(FileObject dir) throws FileSystemException {
		List<FileObject> files = new ArrayList<FileObject>();
		if (dir == null || !dir.exists() || !(dir.getType() == FileType.FOLDER))
			return files;
		for (FileObject file : dir.getChildren()) {
			if (ignore.contains(file.getName().getBaseName()))
				continue;
			if (file.getType() == FileType.FOLDER)
				files.addAll(tree(file));
			else if (file.getType() == FileType.FILE) {
				System.out.println(file.getName().getPath());
				if (path != null
						&& !FilenameUtils.wildcardMatch(file.getName()
								.getPath(), path))
					continue;
				files.add(file);
			}
		}
		return files;
	}

	protected FileObject resolveFile(URL url) throws FileSystemException {
		return VFS.getManager().resolveFile(url.toString());
	}
}
